<?php

class Agi
{

    static public function bootstrap()
    {
        /**
         * register autoload
         */
        spl_autoload_register(array(
            'Agi',
            'autoload'
        ));

        require_once 'system/agi/exception.php';

        require_once 'system/debug.php';

        require_once 'system/cache.php';

        require_once 'system/log.php';

        /**
         * register error handler
         */
        set_error_handler(array(
            'Agi',
            'handle_error'
        ));

        /**
         * register exception handler
         */
        set_exception_handler(array(
            'Agi',
            'handle_exception'
        ));

        /**
         * register shutdown handler
         */
        register_shutdown_function(array(
            'Agi',
            'handle_shutdown'
        ));
    }

    /**
     * load configuration file
     * it seems always return array
     * @return array
     */
    static public function load_config($file, $offset = null, $dir = null)
    {
        if (null == $dir)
        {
            $dir = CONFIG_PATH;
        }

        $filename = $dir . '/' . $file;

        if (!file_exists($filename))
        {
            throw new Exception("Invalid configuration file under config directory $file");
        }

        $data =
        include $filename;

        if ($offset)
        {
            if (!isset($data[$offset]))
            {

                throw new Exception("invalid configuration offset $file:$offset");
            }
            return $data[$offset];
        }
        return $data;
    }

    /**
     * find class
     * @param string $class_name
     * @return true/false
     */
    static public function has_class($class_name)
    {
        return class_exists($class_name) or self::autoload($class_name);
    }

    /**
     * autoload class
     * @param string $class_name
     * @return true/false
     */
    static public function autoload($class_name)
    {
        if ($filename = self::find_class($class_name))
        {
            require_once ROOT_PATH . '/' . $filename;
            return true;
        }
        return false;
    }

    /**
     * find a file in filesystem cascadue
     * @param string $filename
     * @return full path if exists or null otherwise
     */
    static public function find_class($class_name)
    {

        /**
         * load in internal system & application
         */
        $filename = str_replace('_', '/', strtolower($class_name)) . '.php';

        if (file_exists(ROOT_PATH . '/application/module/' . $filename))
        {
            return '/application/module/' . $filename;
        }

        if (file_exists(ROOT_PATH . '/system/' . $filename))
        {
            return '/system/' . $filename;
        }

        /**
         * load in externals library
         */
        $filename = str_replace('_', '/', $filename) . '.php';

        if (file_exists(ROOT_PATH . '/library/' . $filename))
        {
            return '/library/' . $filename;
        }

        return false;
    }

    /**
     * factory a resource object
     *
     * @param      string     $name
     * @param      string     $ext
     * @return     Object
     */
    static public function get_resource($name, $ext = null)
    {
        if (self::has_class($class_name = self::sanitize_class($name)))
        {
            return new $class_name;
        }

        throw new Exception("class $name $ext does not exists!");
    }

    /**
     * @param     string $name
     * @param     string $ext
     * @return    string class name
     */
    static public function sanitize_class($name, $ext)
    {
        if ($ext)
        {
            $name = trim(str_replace('@', '.' . $ext . '.', $name), '.');
        }
        return implode('_', array_map('ucfirst', explode('.', $name)));
    }

    /**
     * handle error
     * @param  int     $errorno
     * @param  string  $errstr
     * @param  string  $errfile
     * @param  int     $errline
     * @param  handle  $errcontext
     */
    static public function handle_error($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
    {
        Log::write(sprintf('[%1$d] %2$s (%3$s) [%4$d]' . PHP_EOL . '%5$s', $errno, $errstr, $errfile, $errline, debug::get_backtrace()));
        return 1;
    }

    /**
     * handle exception
     * @param Exception $exception
     * @return true/false
     */
    static public function handle_exception($exception)
    {
        Log::write(debug::get_backtrace() . PHP_EOL . $exception -> getMessage());
        return 1;
    }

    /**
     * handle shutdown
     */
    static public function handle_shutdown()
    {
        /**
         * code here
         */
    }

}
